import d from "debug";
import { getLogger, initWorkerDebug } from "../log";
import { isEmpty } from "../lodash";

export interface IWorkerMessage {
  type: number | string;
  data: any;
}

/**
 * 公共消息分布在 0~999 之间
 *
 * 自定义消息的起始为 1000
 */
export enum NormalMessageType {
  DEBUG = 0, // 传输 Debug 相关参数
  STARTED, // 初始化完毕后通过此消息通知其他服务
  CFG, // 发送必要的配置参数命令，配置会存储在 cfg 变量中
}

type WebWorkerHandlerFunc = (type: number | string, data: any) => void;

export interface IWebWorkerHandler {
  logger: d.Debugger;
  cfg: Record<string, unknown>;
  name: string;

  /**
   * worker 启动后的入口函数
   * 在此函数内完成 必要的初始化工作
   */
  init(): void;

  onMessage(e: MessageEvent<IWorkerMessage>): void;

  postMessage(message: IWorkerMessage): void;

  /**
   * 向处理器中增加一个 处理函数，同一个类型只能有一个处理函数
   * @param type 类型
   * @param handler
   */
  addHandler(type: string | number, handler: WebWorkerHandlerFunc): void;

  /**
   * 获取当前的处理函数
   * @param type
   */
  getHandler(type: number | string): WebWorkerHandlerFunc | undefined;

  /**
   * 删除已有处理函数
   * @param type
   */
  removeHandler(type: string | number): void;
}

export class WebWorkerBase implements IWebWorkerHandler {
  cfg: Record<string, any> = {};
  logger: d.Debugger = getLogger("ys-ts.ts.web-worker");
  name = "";
  handlers: Map<string | number, WebWorkerHandlerFunc> = new Map<
    string | number,
    WebWorkerHandlerFunc
  >();

  init(): void {
    // 根据 worker 是否存在名字确定 logger
    this.logger = getLogger(
      `ys-ts.ts.web-worker${isEmpty(this.name) ? "" : "." + this.name}`
    );

    // 注册默认处理函数
    initWorkerDebug();
    // 处理 debug
    this.handlers.set(NormalMessageType.DEBUG, (type, data) => {
      this.debugHandler(type, data);
    });

    this.handlers.set(NormalMessageType.CFG, (type, data) => {
      this.cfgHandler(type, data);
    });

    self.onmessage = (e: MessageEvent<IWorkerMessage>) => {
      this.onMessage(e);
    };

    this.postMessage({
      type: NormalMessageType.STARTED,
      data: {},
    });
  }

  onMessage(e: MessageEvent<IWorkerMessage>): void {
    const _t = e.data.type;
    this.logger(`接收消息 ${_t}`);
    const func = this.handlers.get(_t);
    if (func) {
      func(_t, e.data.data);
    }
  }

  postMessage(message: IWorkerMessage): void {
    self.postMessage(message);
  }

  addHandler(type: number | string, handler: WebWorkerHandlerFunc): void {
    this.handlers.set(type, handler);
  }

  getHandler(type: number | string): WebWorkerHandlerFunc | undefined {
    return this.handlers.get(type);
  }

  removeHandler(type: string | number): void {
    this.handlers.delete(type);
  }

  private debugHandler(type: string | number, data: string): void {
    console.log("获取测试参数");
    self._d.enable(data);
    this.logger(`${data}`);
  }

  private cfgHandler(type: number | string, data: any) {
    this.logger("获取到配置文件 ", data);
    this.cfg = data;
  }
}

export class WebWorkerStartBase implements IWebWorkerHandler {
  worker!: Worker;
  cfg: Record<string, any> = {};
  logger: d.Debugger = getLogger("ys-ts.ts.web-worker-start");
  name = "";
  handlers: Map<string | number, WebWorkerHandlerFunc> = new Map<
    string | number,
    WebWorkerHandlerFunc
  >();

  /**
   * 启动 worker 的地方
   * @param worker
   */
  startWorker(worker: Worker) {
    this.worker = worker;
    this.init();
  }

  init(): void {
    this.logger = getLogger(
      `ys-ts.ts.web-worker-start${isEmpty(this.name) ? "" : "." + this.name}`
    );

    // 处理函数
    this.addHandler(NormalMessageType.STARTED, (type, data) => {
      this.startHandler();
    });

    this.worker.onmessage = (e: MessageEvent<IWorkerMessage>) => {
      this.onMessage(e);
    };
  }

  onMessage(e: MessageEvent<IWorkerMessage>): void {
    const _t = e.data.type;
    this.logger(`接收消息 ${_t}`);
    const func = this.handlers.get(_t);
    if (func) {
      func(_t, e.data.data);
    }
  }

  postMessage(message: IWorkerMessage): void {
    this.worker.postMessage(message);
  }

  addHandler(type: number | string, handler: WebWorkerHandlerFunc): void {
    this.handlers.set(type, handler);
  }

  getHandler(type: number | string): WebWorkerHandlerFunc | undefined {
    return this.handlers.get(type);
  }

  removeHandler(type: string | number): void {
    this.handlers.delete(type);
  }

  private startHandler() {
    console.log(`[index] `, this);
    this.postMessage({
      type: NormalMessageType.DEBUG,
      // @ts-ignore
      data: window._d.namespaces,
    });
  }
}
